#include <stdbool.h>
#include "main.h"
#include "device.h"
#include "serial.h"
#include "board.h"
#include "device_types.h"
#include "pilink/pilink_boot.h"
#include <string.h>

// 外部声明
extern struct flash_sector_s stm32f405_sectors[];
extern struct flash_describer_s stm32f405_desc;

void delay_ms(unsigned int x)
{
  while(x > 0){
    for(volatile int i = 0; i < 500; i++);
    x--;
  }
}

int board_jump_to_app(void);

int litos_serial_init(struct pilink_channel_s *ch)
{
  ch->device = lt_dev_open("ttyS1", O_RDWR | LT_DEVICE_FLAG_INT_TX | LT_DEVICE_FLAG_INT_RX);

  if(ch->device > -1){
    struct lt_serial_cfg_s cfg = serial_default_cfg;
    cfg.buad_rate = 115200;
    lt_dev_ioctl(ch->device, LT_DEVICE_CTRL_CONFIG, &cfg);
  }
  return 0;
}

int litos_serial_deinit(struct pilink_channel_s *ch)
{
  lt_dev_close(ch->device);
}

int litos_serial_recv(struct pilink_channel_s *ch, unsigned char *buf, int len)
{
  return lt_dev_read(ch->device, buf, len, 0);
}
int litos_serial_send(struct pilink_channel_s *ch, unsigned char *buf, int len)
{
  return lt_dev_write(ch->device, buf, len, 0);
}

struct pilink_channel_s     litos_serial_channel = {.init = litos_serial_init, 
                                                    .recv = litos_serial_recv, 
                                                    .send = litos_serial_send,
                                                    .deinit = litos_serial_deinit};

struct pilink_transceiver_s litos_serial_transceiver;

void pilink_channel_puts(struct pilink_channel_s ch, char *str)
{
  int len = strlen(str);

  lt_dev_write(ch.device, str, len, 0);
}

void pilink_terminal_puts(char *str)
{
  struct pilink_terminal_data_s terminal_data;

  terminal_data.msg_len = 0;
  for(int i = 0; i < 128; i++){
    if(str[i] != '\0'){
      terminal_data.msg[i] = str[i];
      terminal_data.msg_len++;
    }else{
      break;
    }
  }

  if(terminal_data.msg_len > 0){
    pilink_transceiver_send(&litos_serial_transceiver, PILINK_TYPE_TERMINAL, &terminal_data, sizeof(terminal_data));
  }
}

// 全局变量
static int flash_fd = -1;
static bool in_bootloader = false;  

int main_counter = 0;

struct gpio_info_s led1 = {.pin = 5, .mode = GPIO_MODE_OUTPUT, .status = 0};
struct gpio_info_s led2 = {.pin = 6, .mode = GPIO_MODE_OUTPUT, .status = 0};

// 处理固件数据包
static void handle_boot_data(struct pilink_struct_boot_data_s *data)
{
    // 检查地址对齐
    if (data->addr & 0x3) {
        pilink_terminal_puts("Error: Address must be 4-byte aligned\r\n");
        return;
    }

    // 写入 Flash
    struct flash_program_s prog = {
        .addr = data->addr,
        .data = data->data
    };
    
    if (lt_dev_ioctl(flash_fd, FLASH_CTRL_PROGRAM_WORD, &prog) < 0) {
        pilink_terminal_puts("Error: Failed to program flash\r\n");
        return;
    }

    // 验证数据
    unsigned int read_data;
    if (lt_dev_read(flash_fd, &read_data, sizeof(read_data), data->addr) < 0) {
        pilink_terminal_puts("Error: Failed to verify data\r\n");
        return;
    }

    if (read_data != data->data) {
        pilink_terminal_puts("Error: Data verification failed\r\n");
        return;
    }

    // 发送确认消息
    struct pilink_struct_boot_ack_s ack = {
        .addr = data->addr,
        .data = read_data,
    };

    pilink_transceiver_send(&litos_serial_transceiver, PILINK_TYPE_BOOT_ACK, &ack, sizeof(ack));
}

// 命令处理函数
static void handle_boot_cmd(struct pilink_struct_boot_cmd_s *cmd)
{
    in_bootloader = true;

    pilink_terminal_puts("CMD\r\n");
    
    switch (cmd->cmd) {
        case PILINK_TYPE_BOOT_CMD_ABORT_BOOT:
            pilink_terminal_puts("Aborted\r\n");
            break;
            
        case PILINK_TYPE_BOOT_CMD_STA_UGD:
            // 打开 Flash 设备
            if (flash_fd < 0) {
                flash_fd = lt_dev_open("flash", O_RDWR);
                if (flash_fd < 0) {
                    pilink_terminal_puts("Error: Failed to open flash device\r\n");
                    return;
                }
            }
            
            // 解锁 Flash
            if (lt_dev_ioctl(flash_fd, FLASH_CTRL_UNLOCK, NULL) < 0) {
                pilink_terminal_puts("Error: Failed to unlock flash\r\n");
                return;
            }

            struct pilink_struct_boot_ack_s ack = {
              .addr = 0x00000000,
              .data = 0x00001234,
            };

            pilink_transceiver_send(&litos_serial_transceiver, PILINK_TYPE_BOOT_ACK, &ack, sizeof(ack));

            pilink_terminal_puts("Upgrading...\r\n");
            break;
        case PILINK_TYPE_BOOT_CMD_END_UGD:
            // 打开 Flash 设备
            if (flash_fd > -1) {
                lt_dev_close(flash_fd);
                flash_fd = -1;
            }

            pilink_terminal_puts("Upgraded\r\n");
            break;
            
        case PILINK_TYPE_BOOT_CMD_ERASE:
            if (flash_fd < 0) {
                flash_fd = lt_dev_open("flash", O_RDWR);
                if (flash_fd < 0) {
                    pilink_terminal_puts("Error: Failed to open flash device\r\n");
                    return;
                }
            }
            
            pilink_terminal_puts("Erasing...\r\n");
            
            // 执行全片擦除
            if (lt_dev_ioctl(flash_fd, FLASH_CTRL_ERASE_ALL, NULL) < 0) {
                pilink_terminal_puts("Error: Failed to erase flash\r\n");
                return;
            }
            
            pilink_terminal_puts("Erased\r\n");
            break;
            
        case PILINK_TYPE_BOOT_CMD_RESTART:
            pilink_terminal_puts("Restarting...\r\n");
            
            // 关闭所有设备
            if (flash_fd >= 0) {
                lt_dev_ioctl(flash_fd, FLASH_CTRL_LOCK, NULL);
                lt_dev_close(flash_fd);
                flash_fd = -1;
            }

            delay_ms(1000);
            
            // 系统复位
            NVIC_SystemReset();
            while(1); // 等待复位
            break;
            
        default:
            pilink_terminal_puts("Unknown command\r\n");
            break;
    }
}

// PiLink 协议处理函数
void bl_pilink_handler(struct pilink_transceiver_s *transceiver, unsigned short type, void *data, int len)
{
    if(led2.status != 0){
        led2.status = 0;
    }else{
        led2.status = 200;
    }
    switch (type) {
        case PILINK_TYPE_BOOT_CMD:
            if (len == sizeof(struct pilink_struct_boot_cmd_s)) {
                struct pilink_struct_boot_cmd_s *cmd = (struct pilink_struct_boot_cmd_s *)data;
                handle_boot_cmd(cmd);
            }
            break;
            
        case PILINK_TYPE_BOOT_DATA:
            if (len == sizeof(struct pilink_struct_boot_data_s)) {
                struct pilink_struct_boot_data_s *boot_data = (struct pilink_struct_boot_data_s *)data;
                handle_boot_data(boot_data);
            }
            break;
            
        case PILINK_TYPE_TERMINAL:
            if (len == sizeof(struct pilink_terminal_data_s)) {
                struct pilink_terminal_data_s *terminal_data = (struct pilink_terminal_data_s *)data;
                // 处理终端消息
                if (terminal_data->msg_len > 0) {
                    terminal_data->msg[terminal_data->msg_len] = '\0';
                    pilink_terminal_puts(terminal_data->msg);
                }
            }
            break;
            
        default:
            break;
    }
}

int main(void)
{
    // 初始化板级硬件
    board_initialize();
    
    // 初始化串口
    pilink_transceiver_init(&litos_serial_transceiver, 0x01, &litos_serial_channel, bl_pilink_handler);
    
    // 打印启动信息
    //bl_put_logo();
    pilink_terminal_puts("System initialized\r\n");
    pilink_terminal_puts("Waiting for command...\r\n");

        // 初始化 LED
    int gpio_fd = lt_dev_open("gpio", O_RDWR);

    lt_dev_ioctl(gpio_fd, LT_DEVICE_CTRL_CONFIG, &led1);
    lt_dev_ioctl(gpio_fd, LT_DEVICE_CTRL_CONFIG, &led2);
    lt_dev_write(gpio_fd, &led1, sizeof(led1), 0);
    lt_dev_write(gpio_fd, &led2, sizeof(led2), 0);
    
    // 初始化变量
    
    int waiting_time = 15000;  // 5秒等待时间
    int jump_failed = 0;

    // 主循环
    while(1) {
        // 运行通信协议
        pilink_transceiver_run(&litos_serial_transceiver);
    
        // 等待时间计数
        if (!in_bootloader) {
            if (main_counter % 1000 == 0) {  // 每秒更新一次
                pilink_terminal_puts(".");
                waiting_time -= 1000;
                
                if (waiting_time <= 0) {
                    // 跳转到应用程序
                    pilink_terminal_puts("No command received, jumping to application...\r\n");
                    
                    if (board_jump_to_app() < 0) {
                        pilink_terminal_puts("Failed to jump to application!\r\n");
                        pilink_terminal_puts("Please download the application first!\r\n");
                        in_bootloader = true;  // 失败后进入 bootloader 模式
                        jump_failed = 1;
                    }
                }
            }

            led1.status = (main_counter % 200) < 100 ? 1 : 0; 
        }else{
            led1.status = (main_counter % 800) < 400 ? 1 : 0;
        }

        lt_dev_write(gpio_fd, &led2, sizeof(led2), 0);
        lt_dev_write(gpio_fd, &led1, sizeof(led1), 0);
        
        main_counter++;
        delay_ms(1);
    }
}
